package com.cimu.redis.config;

import com.cimu.redis.properties.ClusterConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.time.Duration;


/**
 * Redis缓存配置类
 */
@Configuration
@EnableRedisRepositories
public class RedisConfig extends CachingConfigurerSupport {
//    //哨兵配置
//    @Value("#{'${spring.redis.sentinel.nodes}'.split(',')}")
//    private List<String> clusterSentinels;
//    //哨兵配置
//    @Value("${spring.redis.sentinel.master}")
//    private String sentinelMaster;

    @Autowired
    private ClusterConfigProperties clusterProperties;

    /**
     * 自定义缓存key生成策略
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuffer sb = new StringBuffer();
                sb.append(target.getClass().getName()).append("_");
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append("_").append(obj == null ? "" : obj.toString());
                }
                return sb.toString();
            }
        };
    }

    //@Qualifier("clusterConnectionFactory") 根据需要配置为那个 就使用哪个bean name
    /**
     * 缓存管理器
     */
    @Bean
    @Primary
    public CacheManager cacheManager(@Qualifier("clusterConnectionFactory") RedisConnectionFactory factory) {
        // 设置缓存有效期一小时
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory))
                .cacheDefaults(redisCacheConfiguration).build();
    }

    //@Qualifier("clusterConnectionFactory") 根据需要配置为那个 就使用哪个bean name
    /**
     * 5分钟失效缓存管理器
     */
    @Bean
    public CacheManager fiveMinutesManager(@Qualifier("clusterConnectionFactory") RedisConnectionFactory factory) {
        // 设置缓存有效期5分钟
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(5));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory))
                .cacheDefaults(redisCacheConfiguration).build();
    }

    //@Qualifier("clusterConnectionFactory") 根据需要配置为那个 就使用哪个bean name
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Serializable, Serializable> redisTemplate(@Qualifier("clusterConnectionFactory") RedisConnectionFactory factory) {
        RedisTemplate<Serializable, Serializable> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //设置序列化工具
        setSerializer(template);
        template.afterPropertiesSet();
        return template;
    }

    //@Qualifier("clusterConnectionFactory") 根据需要配置为那个 就使用哪个bean name
    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(@Qualifier("clusterConnectionFactory") RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(factory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setValueSerializer(stringRedisSerializer);
        template.setKeySerializer(stringRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 设置序列化工具
     *
     * @param template RedisTemplate
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private void setSerializer(RedisTemplate template) {
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        template.setDefaultSerializer(jackson2JsonRedisSerializer);//发布订阅的时候，传输对象如果使用@Builder注解，需要实现无参构造函数
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
    }

    //如果连接单个redis，那么使用这个配置
//    @Autowired
//    private RedisConnectionFactory factory;

//    /**
//     * 如果使用哨兵，使用这个配置
//     *
//     * @return RedisConnectionFactory
//     */
//    @Bean(name="sentinelConnectionFactory")
//    public RedisConnectionFactory sentinelConnectionFactory() {
//        if(this.clusterSentinels.size()<=0 ||
//                this.clusterSentinels.get(0).length()==0){
//            return null;
//        }
//        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(sentinelConfig(),
//                LettuceClientConfiguration.defaultConfiguration());
//        //如果你的redis设置了密码，那么需要在这里指定密码
//        lettuceConnectionFactory.setPassword("zxcv1234");
//        return lettuceConnectionFactory;
//    }
//    /**
//     * redis哨兵配置
//     * @return
//     */
//    @Bean
//    public RedisSentinelConfiguration sentinelConfig(){
//        if(this.clusterSentinels.size()<=0 ||
//                this.clusterSentinels.get(0).length()==0){
//            return null;
//        }
//        return new RedisSentinelConfiguration(this.sentinelMaster,
//                new HashSet<>(this.clusterSentinels));
//    }

    /**
     * redis 集群配置
     */
    @Bean
    public RedisClusterConfiguration clusterConfig() {
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterProperties.getNodes());
        redisClusterConfiguration.setMaxRedirects(clusterProperties.getMaxRedirects().intValue());
        return redisClusterConfiguration;
    }

    /**
     * redis 集群配置
     */
    @Bean(name = "clusterConnectionFactory")
    public LettuceConnectionFactory getConnectionFactory(RedisClusterConfiguration clusterConfig) {
        return new LettuceConnectionFactory(clusterConfig);
    }

}